package io.github.harmonly.skyblock.util;

import com.google.gson.*;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

public class JavaUtil {

    private static final Gson gson = new GsonBuilder()
            .setLenient().create();
    public static final String DATA_FOLDER = "./plugins/SkyBlock/";

    public static JsonElement toJson(Object object) {
        return gson.toJsonTree(object);
    }

    // 从文件中读取并解析JSON对象
    public static JsonObject readFile(String fileName) {
        try (FileReader reader = new FileReader(DATA_FOLDER + fileName)) {
            return gson.fromJson(reader, JsonObject.class);
        } catch (IOException | JsonSyntaxException e) {
            return new JsonObject();
        }
    }

    public static JsonObject readJson(String fileName) {
        return readFile(fileName);
    }

    public static JsonObject readJson(InputStream inputStream) {
        return gson.fromJson(new InputStreamReader(inputStream, StandardCharsets.UTF_8), JsonObject.class);
    }

    public static void writeJson(JsonElement element, String filePath) {
        try (FileWriter fileWriter = new FileWriter(DATA_FOLDER + filePath)) {
            fileWriter.write(element.toString());
            fileWriter.flush();
        } catch (IOException exception) {
            exception.printStackTrace();
        }
    }

    public static boolean exist(String path) {
        return new File(path).exists();
    }

    public static void mkdirs(String path) {
        mkdirs(path, false);
    }

    public static void mkdirs(String path, boolean isPlugin) {
        File dir = new File((isPlugin ? DATA_FOLDER : "") + path);
        if (!dir.exists()) {
            dir.mkdirs();
        }
    }

    public static void deleteDirectory(String folderPath) {
        File folder = new File(folderPath);
        File[] files = folder.listFiles();
        if (!folder.isDirectory() || files == null) {
            return;
        }
        for (File file : files) {
            if (file.isDirectory()) {
                deleteDirectory(file.getPath());
            }
            file.delete();
        }
        folder.delete();
    }

    public static void deleteFile(String filePath) {
        File file = new File(filePath);
        if (file.isFile()) {
            file.delete();
        }
    }

    /**
     * 压缩整个文件夹到一个ZIP文件
     *
     * @param folderPath 要压缩的文件夹路径
     * @param zipFile    目标ZIP文件路径
     */
    public static void zipDirectory(String folderPath, String zipFile) {
        File folder = new File(folderPath);
        if (!folder.isDirectory()) {
            System.err.println("The provided folderName is not a directory.");
            return;
        }
        try (FileOutputStream fos = new FileOutputStream(zipFile);
             ZipOutputStream zos = new ZipOutputStream(fos)) {

            zipFolder(folder, folder.getName(), zos);
            System.out.println("Directory successfully compressed: " + folder.getName());

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 递归压缩文件夹
     *
     * @param folder       当前要压缩的文件夹
     * @param parentFolder 父文件夹的名称，用于ZIP条目路径
     * @param zos          ZIP输出流
     * @throws IOException 如果文件操作失败
     */
    private static void zipFolder(File folder, String parentFolder, ZipOutputStream zos) throws IOException {
        File[] files = folder.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    zipFolder(file, parentFolder + "/" + file.getName(), zos);
                } else {
                    zipFile(file, parentFolder, zos);
                }
            }
        }
    }

    /**
     * 压缩单个文件
     *
     * @param file         要压缩的文件
     * @param parentFolder 父文件夹的名称，用于ZIP条目路径
     * @param zos          ZIP输出流
     * @throws IOException 如果文件操作失败
     */
    private static void zipFile(File file, String parentFolder, ZipOutputStream zos) throws IOException {
        try (FileInputStream fis = new FileInputStream(file)) {
            String zipEntryName = parentFolder + "/" + file.getName();
            ZipEntry zipEntry = new ZipEntry(zipEntryName);
            zos.putNextEntry(zipEntry);

            byte[] buffer = new byte[1024];
            int len;
            while ((len = fis.read(buffer)) > 0) {
                zos.write(buffer, 0, len);
            }

            zos.closeEntry();
        }
    }

    /**
     * 解压缩ZIP文件到指定目录
     *
     * @param zipFile ZIP文件路径
     * @param destDir 目标目录路径
     */
    public static void unzipFile(String zipFile, String destDir) {
        mkdirs(destDir);

        try (FileInputStream fis = new FileInputStream(zipFile);
             ZipInputStream zis = new ZipInputStream(fis)) {

            ZipEntry zipEntry = zis.getNextEntry();
            while (zipEntry != null) {
                String filePath = destDir + File.separator + zipEntry.getName();
                if (!zipEntry.isDirectory()) {
                    extractFile(zis, filePath);
                } else {
                    mkdirs(filePath);
                }
                zis.closeEntry();
                zipEntry = zis.getNextEntry();
            }
            System.out.println("File successfully uncompressed");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 从ZIP输入流中提取文件
     *
     * @param zis      ZIP输入流
     * @param filePath 目标文件路径
     * @throws IOException 如果文件操作失败
     */
    private static void extractFile(ZipInputStream zis, String filePath) throws IOException {
        File newFile = new File(filePath);
        mkdirs(newFile.getParent());
        try (FileOutputStream fos = new FileOutputStream(newFile)) {
            byte[] buffer = new byte[1024];
            int len;
            while ((len = zis.read(buffer)) > 0) {
                fos.write(buffer, 0, len);
            }
        }
    }
}
